package com.nefu.softlab.xjwc.service.impl;

import com.nefu.softlab.xjwc.common.Constant;
import com.nefu.softlab.xjwc.mapper.ActivityMapper;
import com.nefu.softlab.xjwc.mapper.DocumentMapper;
import com.nefu.softlab.xjwc.mapper.ProjectMapper;
import com.nefu.softlab.xjwc.model.Activity;
import com.nefu.softlab.xjwc.model.Document;
import com.nefu.softlab.xjwc.model.Project;
import com.nefu.softlab.xjwc.service.DocumentService;
import com.nefu.softlab.xjwc.utils.FileUtil;
import com.nefu.softlab.xjwc.utils.JSONResult;
import com.nefu.softlab.xjwc.utils.LoggerUtil;
import com.nefu.softlab.xjwc.utils.XJWCException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import static com.nefu.softlab.xjwc.common.Constant.UPLOAD_PATH_PREFIX;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * @author LiXiwen
 * @date 2020/2/8 11:24
 */
@Service
public class DocumentServiceImpl implements DocumentService {

    private final DocumentMapper documentMapper;
    private final ActivityMapper activityMapper;
    private final ProjectMapper projectMapper;
    private final LoggerUtil logger;

    @Autowired
    public DocumentServiceImpl(DocumentMapper documentMapper, ActivityMapper activityMapper, ProjectMapper projectMapper, LoggerUtil logger) {
        this.documentMapper = documentMapper;
        this.activityMapper = activityMapper;
        this.projectMapper = projectMapper;
        this.logger = logger;
    }

    @Override
    public JSONResult uploadDocument(MultipartFile[] files, Document document) throws XJWCException {
        Integer projectId = document.getProjectId();
        Activity activity = activityMapper.selectActivityByProjectId(projectId).get(0);
        Project project = new Project();
        project.setProjectId(projectId);
        // 因为还没上传文件，所以不能和文件表联合查，傻了傻了
        project = projectMapper.selectAllProject2(project).get(0);

        // 项目文件夹路径
        String path = UPLOAD_PATH_PREFIX + activity.getActivityId() + "-" + activity.getName()
                + "/" + projectId + "-" + project.getName() + "/";

        String delPath = activity.getActivityId() + "-" + activity.getName()
                + "/" + projectId + "-" + project.getName();

        System.err.println("uploadDocument --> 项目文件夹路径 : " + path);

        // 如果已经存在项目对应文件夹, 就删除, 存的是项目文件夹路径
        List<String> names = documentMapper.getFilePath(projectId);

        try {
            if (names != null || names.size() > 0) {
                deleteDocument(projectId, delPath);
            }
            document.setDocName(path);
            documentMapper.addDocument(document);

            // 异步上传文件
            if (files == null || files.length <= 0) {
                FileUtil.mkdir(activity.getActivityId() + "-" + activity.getName()
                        + "/" + projectId + "-" + project.getName());
                return JSONResult.ok("上传成功");
            } else {
                Future<Boolean> future = FileUtil.uploadFileAsync(files[0], path);
                if (future.get()) {
                    return JSONResult.ok("上传成功");
                }
            }
        } catch (InterruptedException e) {
            logger.error(e.getMessage());
            return JSONResult.errorMessage("上传失败!" + e.getMessage());
        } catch (ExecutionException e) {
            logger.error(e.getMessage());
            return JSONResult.errorMessage("上传失败!" + e.getMessage());
        }
        return JSONResult.errorMessage("上传失败!");
    }


    @Override
    public String updateDocument(MultipartFile[] files, Document document) {
        Integer projectId = document.getProjectId();
        Activity activity = activityMapper.selectActivityByProjectId(projectId).get(0);
        Project project = new Project();
        project.setProjectId(projectId);

        // 可能要把url改成空
        if (null != document.getDocUrl()) {
            documentMapper.updateDocUrlByProjectId(document);
        }

        // 更新项目时已经把项目名更新了。又因为如果文件为空也会掉这个方法
        project = projectMapper.selectAllProject2(project).get(0);

        // 获取到旧路径名
        String oldProjectDir = documentMapper.getFilePath(projectId).get(0);

        String newProjectDir = UPLOAD_PATH_PREFIX
                + activity.getActivityId() + "-" + activity.getName()
                + "/" + projectId + "-" + project.getName() + "/";

        String path = activity.getActivityId() + "-" + activity.getName()
                + "/" + projectId + "-" + project.getName();

        // 如果新路径和旧路径不同，更新文件表
        if (!newProjectDir.equals(oldProjectDir)) {
            System.out.println("oldProjectDir = " + oldProjectDir + " , newProjectDir = " + newProjectDir);
            // 更新文件表的路径名
            documentMapper.updateDocNameByProjectId(oldProjectDir, newProjectDir, projectId);
        }

        // todo ：（已完成，特此标记）：
        //  文件为空，代表要删除原先文件，然后新建一个空文件夹。如果直接新建，不会覆盖之前的文件夹。
        //  文件不为空，代表要替换原先文件，所以要先删除，然后新建和上传。把公有代码提取出来。

        // 先直接删除所有文件，新建一个新的文件夹
        FileUtil.delAllFile(new File(oldProjectDir));
        FileUtil.mkdir(path);

        // 文件为空，代表要删除原先文件，然后新建一个空文件夹，直接新建，不会覆盖之前的文件夹。
        if (files != null && files.length >= 1) {
            System.out.println("files length : " + files.length);
            System.err.println("updateDocument --> 新的项目文件夹路径 : " + newProjectDir);

            // 文件不空，重新执行上传操作, 异步上传方法会报错。找了一下午才找到这个原因
            FileUtil.uploadFileSync(files[0], newProjectDir);
        }

        return "更新文件成功";
    }


    @Override
    public String downloadDocument(Integer projectId, String fileName, HttpServletResponse response, HttpServletRequest request) throws XJWCException {
        Activity tmp = activityMapper.selectActivityByProjectId(projectId).get(0);
        String dir = tmp.getName();
        String path = UPLOAD_PATH_PREFIX + tmp.getActivityId() + "-" + dir + "/" + projectId + "-" + fileName;
        System.out.println("path = " + path);
        File file = new File (path);
        if (!file.exists()) {
            throw new XJWCException("未查询到此文件");
        }
        //获得浏览器信息并转换为大写
        String agent = request.getHeader("User-Agent").toUpperCase();
        boolean f = agent.indexOf("MSIE") > 0 || (agent.indexOf("GECKO") > 0 && agent.indexOf("RV:11") > 0);
        if (f) {
            //微软的浏览器(IE和Edge浏览器)
            try {
                fileName = URLEncoder.encode(fileName, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        } else {
            try {
                fileName = new String(fileName.getBytes("UTF-8"), "iso-8859-1");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        response.setHeader("Content-Disposition", "filename=" + fileName);

        response.setContentType("application/octet-stream");

        try {
            FileInputStream fis = new FileInputStream(path);
            byte[] content = new byte[fis.available()];
            fis.read(content);
            ServletOutputStream sos = response.getOutputStream();
            sos.write(content);
            sos.flush();
            sos.close();
            fis.close();
        } catch (Exception e) {
            return "下载失败";
        }
        return null;
    }

    @Override
    public JSONResult getFileName(Integer projectId) throws XJWCException {
        List<String> names = documentMapper.getFilePath(projectId);
        if (null == names || names.size() <= 0) {
            throw new XJWCException("文件为空");
        }
        return JSONResult.ok(names);
    }

    @Override
    public JSONResult deleteDocument(Integer projectId, String path) throws XJWCException {

        if (documentMapper.deleteDocument(projectId) && FileUtil.deleteDocument(path)) {
            return JSONResult.ok("删除成功");
        }
        return JSONResult.errorMessage("删除失败!");
    }

    @SuppressWarnings("Duplicates")
    @Override
    public Map<String, Object> previewFiles(Integer projectId) {
        Activity activity = activityMapper.selectActivityByProjectId(projectId).get(0);
        Project project = new Project();
        project.setProjectId(projectId);
        project = projectMapper.selectAllProject1(project).get(0);

        String path = UPLOAD_PATH_PREFIX
                + activity.getActivityId() + "-" + activity.getName()
                + "/" + project.getProjectId() + "-" + project.getName() + "/";

        Map<String, Object> res = new HashMap<>(4);

        // 添加了视频和pdf的预览
        List<File> allFile = FileUtil.getAllAvaliableFile(path);
        List<String> list = new ArrayList<>();

        allFile.parallelStream().forEach(file -> {
            String url = Constant.URL_PREFIX + file.getAbsolutePath().replaceFirst(UPLOAD_PATH_PREFIX, "");
            System.out.println("文件访问路径 ---> " + url);
            list.add(url);
        });

        // 网络材料
        String url = documentMapper.selectDocUrls(projectId).get(0);

        res.put("file", list);
        res.put("url", url);

        return res;
    }

    @Override
    public boolean updateDocName(String oldDir, String newDir, Integer activityId) {
        return documentMapper.updateDocName(oldDir, newDir, activityId);
    }

    @Override
    public boolean deleteDocumentsByActivityId(Integer activityId) {
        return documentMapper.deleteDocumentsByActivityId(activityId);
    }
}
